package com.tencent.sr.iris.basic.mp.common.util;

import com.tencent.sr.rmall.common.exception.code.BaseErrorCode;
import com.tencent.sr.rmall.common.exception.code.ErrorCode;
import com.tencent.sr.rmall.common.exception.retail.TRetailBizException;
import com.tencent.sr.rmall.common.exception.retail.TRetailRpcResultException;
import com.tencent.sr.rmall.common.primitive.HttpResult;
import com.tencent.sr.rmall.springbootstarter.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.SharedSecrets;

import javax.annotation.Nullable;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;

/**
 * @author nixiaolin
 * @date 2022/11/13 15:34
 */
public abstract class HttpUtils {

    /**
     * 处理异常
     *
     * @param result
     */
    public static <T> T handleError(HttpResult<T> result) {
        boolean success = result != null;
        AssertUtils.isTrue(success, BaseErrorCode.SYSTEM_ERROR);

        success = result.isSuccess();
        AssertUtils.isTrue(success, new ErrorCode() {
            @Override
            public String getCode() {
                return result.getCode();
            }

            @Override
            public String getDescription() {
                return result.getMsg();
            }
        });

        return result.getData();
    }

    private static final String DOT = ".";

    private static final String INNER_METHOD_SEPARATOR = "$";

    public static <T, R> R httpCall(T request, Function<T, HttpResult<R>> function, @Nullable ErrorCode errorCode) {
        errorCode = Optional.ofNullable(errorCode).orElse(BaseErrorCode.SYSTEM_ERROR);
        StackTraceElement stackTraceElement = SharedSecrets.getJavaLangAccess()
                .getStackTraceElement(new Throwable(), 1);
        String className = stackTraceElement.getClassName();
        Logger log = LoggerFactory.getLogger(className);
        HttpResult<R> result = null;
        try {
            result = function.apply(request);
            if (Objects.nonNull(result) && result.isSuccess()) {
                log.info("{} {} success request:{} response:{}",
                        StringUtils.substringAfterLast(className, DOT), // simpleClassName
                        StringUtils.substringBefore(stackTraceElement.getMethodName(), INNER_METHOD_SEPARATOR), // methodName
                        JsonUtils.toJsonString(request), result);
                return result.getData();
            }
        } catch (Exception e) {
            log.error("{} {} fail exception request:{} response:{}",
                    StringUtils.substringAfterLast(className, DOT), // simpleClassName
                    StringUtils.substringBefore(stackTraceElement.getMethodName(), INNER_METHOD_SEPARATOR), // methodName
                    JsonUtils.toJsonString(request), result, e);
            throw new TRetailRpcResultException(errorCode, e);
        }
        log.error("{} {} fail null request:{} response:{}",
                StringUtils.substringAfterLast(className, DOT), // simpleClassName
                StringUtils.substringBefore(stackTraceElement.getMethodName(), INNER_METHOD_SEPARATOR), // methodName
                JsonUtils.toJsonString(request), result);
        if (Objects.isNull(result)) {
            throw new TRetailBizException(errorCode);
        }
        throw new TRetailBizException(result.getCode(), result.getMsg());
    }
}
